{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp models.RNNPlus"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# RNNPlus\n",
    "\n",
    "> These are RNN, LSTM and GRU PyTorch implementations created by Ignacio Oguiza - timeseriesAI@gmail.com based on:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The idea of including a feature extractor to the RNN network comes from the solution developed by the UPSTAGE team (https://www.kaggle.com/songwonho, \n",
    "https://www.kaggle.com/limerobot and https://www.kaggle.com/jungikhyo). \n",
    "They finished in 3rd position in Kaggle's Google Brain - Ventilator Pressure Prediction competition. They used a Conv1d + Stacked LSTM architecture."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from tsai.imports import *\n",
    "from tsai.utils import *\n",
    "from tsai.data.core import *\n",
    "from tsai.models.layers import *\n",
    "from tsai.models.utils import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class _RNN_Backbone(Module):\n",
    "    def __init__(self, cell, c_in, c_out, seq_len=None, hidden_size=100, n_layers=1, bias=True, rnn_dropout=0, bidirectional=False,\n",
    "                 n_embeds=None, embed_dims=None, cat_pos=None, feature_extractor=None, init_weights=True):\n",
    "        \n",
    "        # Categorical embeddings\n",
    "        if n_embeds is not None:\n",
    "            if embed_dims is None:  \n",
    "                embed_dims = [emb_sz_rule(s) for s in n_embeds]\n",
    "            self.to_cat_embed = MultiEmbedding(c_in, n_embeds, embed_dims=embed_dims, cat_pos=cat_pos)\n",
    "            c_in = c_in + sum(embed_dims) - len(n_embeds)\n",
    "        else:\n",
    "            self.to_cat_embed = nn.Identity()\n",
    "        \n",
    "        # Feature extractor\n",
    "        if feature_extractor:\n",
    "            if isinstance(feature_extractor, nn.Module):  self.feature_extractor = feature_extractor\n",
    "            else: self.feature_extractor = feature_extractor(c_in, seq_len)\n",
    "            c_in, seq_len = output_size_calculator(self.feature_extractor, c_in, seq_len)\n",
    "        else:\n",
    "            self.feature_extractor = nn.Identity()\n",
    "        \n",
    "        # RNN layers\n",
    "        rnn_layers = []\n",
    "        if len(set(hidden_size)) == 1: \n",
    "            hidden_size = hidden_size[0]\n",
    "            if n_layers == 1: rnn_dropout = 0\n",
    "            rnn_layers.append(cell(c_in, hidden_size, num_layers=n_layers, bias=bias, batch_first=True, dropout=rnn_dropout, bidirectional=bidirectional))\n",
    "            rnn_layers.append(LSTMOutput()) # this selects just the output, and discards h_n, and c_n\n",
    "        else: \n",
    "            for i in range(len(hidden_size)):\n",
    "                input_size = c_in if i == 0 else hs * (1 + bidirectional)\n",
    "                hs = hidden_size[i] \n",
    "                rnn_layers.append(cell(input_size, hs, num_layers=1, bias=bias, batch_first=True, bidirectional=bidirectional))\n",
    "                rnn_layers.append(LSTMOutput()) # this selects just the output, and discards h_n, and c_n\n",
    "                if rnn_dropout and i < len(hidden_size) - 1: rnn_layers.append(nn.Dropout(rnn_dropout)) # add dropout to all layers except last\n",
    "        self.rnn = nn.Sequential(*rnn_layers)\n",
    "        self.transpose = Transpose(-1, -2, contiguous=True)\n",
    "        if init_weights: self.apply(self._weights_init) \n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.to_cat_embed(x)\n",
    "        x = self.feature_extractor(x)\n",
    "        x = self.transpose(x)                    # [batch_size x n_vars x seq_len] --> [batch_size x seq_len x n_vars]\n",
    "        x = self.rnn(x)                          # [batch_size x seq_len x hidden_size * (1 + bidirectional)]\n",
    "        x = self.transpose(x)                    # [batch_size x hidden_size * (1 + bidirectional) x seq_len]\n",
    "        return x\n",
    "    \n",
    "    def _weights_init(self, m): \n",
    "        # same initialization as keras. Adapted from the initialization developed \n",
    "        # by JUN KODA (https://www.kaggle.com/junkoda) in this notebook\n",
    "        # https://www.kaggle.com/junkoda/pytorch-lstm-with-tensorflow-like-initialization\n",
    "        for name, params in m.named_parameters():\n",
    "            if \"weight_ih\" in name: \n",
    "                nn.init.xavier_normal_(params)\n",
    "            elif 'weight_hh' in name: \n",
    "                nn.init.orthogonal_(params)\n",
    "            elif 'bias_ih' in name:\n",
    "                params.data.fill_(0)\n",
    "                # Set forget-gate bias to 1\n",
    "                n = params.size(0)\n",
    "                params.data[(n // 4):(n // 2)].fill_(1)\n",
    "            elif 'bias_hh' in name:\n",
    "                params.data.fill_(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class _RNNPlus_Base(nn.Sequential):\n",
    "    def __init__(self, c_in, c_out, seq_len=None, hidden_size=[100], n_layers=1, bias=True, rnn_dropout=0, bidirectional=False,\n",
    "                 n_embeds=None, embed_dims=None, cat_pos=None, feature_extractor=None, fc_dropout=0., last_step=True, bn=False, \n",
    "                 custom_head=None, y_range=None, init_weights=True):\n",
    "\n",
    "        if not last_step: assert seq_len, 'you need to pass a seq_len value'\n",
    "\n",
    "        # Backbone\n",
    "        hidden_size = listify(hidden_size)\n",
    "        backbone = _RNN_Backbone(self._cell, c_in, c_out, seq_len=seq_len, hidden_size=hidden_size, n_layers=n_layers, \n",
    "                                 n_embeds=n_embeds, embed_dims=embed_dims, cat_pos=cat_pos, feature_extractor=feature_extractor,\n",
    "                                 bias=bias, rnn_dropout=rnn_dropout,  bidirectional=bidirectional, init_weights=init_weights)\n",
    "\n",
    "        # Head\n",
    "        self.head_nf = hidden_size * (1 + bidirectional) if isinstance(hidden_size, Integral) else hidden_size[-1] * (1 + bidirectional) \n",
    "        if custom_head: \n",
    "            if isinstance(custom_head, nn.Module): head = custom_head\n",
    "            else: head = custom_head(self.head_nf, c_out, seq_len)\n",
    "        else: head = self.create_head(self.head_nf, c_out, seq_len, last_step=last_step, fc_dropout=fc_dropout, bn=bn, y_range=y_range)\n",
    "        super().__init__(OrderedDict([('backbone', backbone), ('head', head)]))\n",
    "\n",
    "    def create_head(self, nf, c_out, seq_len, last_step=True, fc_dropout=0., bn=False, y_range=None):\n",
    "        if last_step:\n",
    "            layers = [LastStep()]\n",
    "        else:\n",
    "            layers = [Flatten()]\n",
    "            nf *= seq_len\n",
    "        if bn: layers += [nn.BatchNorm1d(nf)]\n",
    "        if fc_dropout: layers += [nn.Dropout(fc_dropout)]\n",
    "        layers += [nn.Linear(nf, c_out)]\n",
    "        if y_range: layers += [SigmoidRange(*y_range)]\n",
    "        return nn.Sequential(*layers)\n",
    "\n",
    "\n",
    "class RNNPlus(_RNNPlus_Base):\n",
    "    _cell = nn.RNN\n",
    "\n",
    "class LSTMPlus(_RNNPlus_Base):\n",
    "    _cell = nn.LSTM\n",
    "\n",
    "class GRUPlus(_RNNPlus_Base):\n",
    "    _cell = nn.GRU"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bs = 16\n",
    "c_in = 3\n",
    "seq_len = 12\n",
    "c_out = 2\n",
    "xb = torch.rand(bs, c_in, seq_len)\n",
    "test_eq(RNNPlus(c_in, c_out)(xb).shape, [bs, c_out])\n",
    "test_eq(RNNPlus(c_in, c_out, hidden_size=100, n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5)(xb).shape, [bs, c_out])\n",
    "test_eq(RNNPlus(c_in, c_out, hidden_size=[100, 50, 10], bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5)(xb).shape, [bs, c_out])\n",
    "test_eq(RNNPlus(c_in, c_out, hidden_size=[100], n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5)(xb).shape, \n",
    "        [bs, c_out])\n",
    "test_eq(LSTMPlus(c_in, c_out, hidden_size=100, n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5)(xb).shape, [bs, c_out])\n",
    "test_eq(GRUPlus(c_in, c_out, hidden_size=100, n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5)(xb).shape, [bs, c_out])\n",
    "test_eq(RNNPlus(c_in, c_out, seq_len, last_step=False)(xb).shape, [bs, c_out])\n",
    "test_eq(RNNPlus(c_in, c_out, seq_len, last_step=False)(xb).shape, [bs, c_out])\n",
    "test_eq(RNNPlus(c_in, c_out, seq_len, hidden_size=100, n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5, last_step=False)(xb).shape, \n",
    "        [bs, c_out])\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, last_step=False)(xb).shape, [bs, c_out])\n",
    "test_eq(GRUPlus(c_in, c_out, seq_len, last_step=False)(xb).shape, [bs, c_out])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "feature_extractor = MultiConv1d(c_in, kss=[1,3,5,7])\n",
    "custom_head = nn.Sequential(Transpose(1,2), nn.Linear(8,8), nn.SELU(), nn.Linear(8, 1), Squeeze())\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, hidden_size=[32,16,8,4], bidirectional=True, \n",
    "                 feature_extractor=feature_extractor, custom_head=custom_head)(xb).shape, [bs, seq_len])\n",
    "feature_extractor = MultiConv1d(c_in, kss=[1,3,5,7], keep_original=True)\n",
    "custom_head = nn.Sequential(Transpose(1,2), nn.Linear(8,8), nn.SELU(), nn.Linear(8, 1), Squeeze())\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, hidden_size=[32,16,8,4], bidirectional=True, \n",
    "                 feature_extractor=feature_extractor, custom_head=custom_head)(xb).shape, [bs, seq_len])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bs = 16\n",
    "c_in = 3\n",
    "seq_len = 12\n",
    "c_out = 2\n",
    "x1 = torch.rand(bs,1,seq_len)\n",
    "x2 = torch.randint(0,3,(bs,1,seq_len))\n",
    "x3 = torch.randint(0,5,(bs,1,seq_len))\n",
    "xb = torch.cat([x1,x2,x3],1)\n",
    "\n",
    "custom_head = partial(create_mlp_head, fc_dropout=0.5)\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, last_step=False, custom_head=custom_head)(xb).shape, [bs, c_out])\n",
    "custom_head = partial(create_pool_head, concat_pool=True, fc_dropout=0.5)\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, last_step=False, custom_head=custom_head)(xb).shape, [bs, c_out])\n",
    "custom_head = partial(create_pool_plus_head, fc_dropout=0.5)\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, last_step=False, custom_head=custom_head)(xb).shape, [bs, c_out])\n",
    "custom_head = partial(create_conv_head)\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, last_step=False, custom_head=custom_head)(xb).shape, [bs, c_out])\n",
    "test_eq(LSTMPlus(c_in, c_out, seq_len, hidden_size=[100, 50], n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True)(xb).shape, [bs, c_out])\n",
    "\n",
    "n_embeds = [3, 5]\n",
    "cat_pos = [1, 2]\n",
    "custom_head = partial(create_conv_head)\n",
    "m = LSTMPlus(c_in, c_out, seq_len, hidden_size=[100, 50], n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, n_embeds=n_embeds, cat_pos=cat_pos)\n",
    "test_eq(m(xb).shape, [bs, c_out])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tsai.data.all import *\n",
    "from tsai.models.utils import *\n",
    "dsid = 'NATOPS' \n",
    "bs = 16\n",
    "X, y, splits = get_UCR_data(dsid, return_split=False)\n",
    "tfms  = [None, [Categorize()]]\n",
    "dls = get_ts_dls(X, y, tfms=tfms, splits=splits, bs=bs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sequential(\n",
      "  (0): LastStep()\n",
      "  (1): Linear(in_features=100, out_features=6, bias=True)\n",
      ")\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: left;\">\n",
       "      <th>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>valid_loss</th>\n",
       "      <th>accuracy</th>\n",
       "      <th>time</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1.785528</td>\n",
       "      <td>1.690278</td>\n",
       "      <td>0.233333</td>\n",
       "      <td>00:01</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = build_ts_model(LSTMPlus, dls=dls)\n",
    "print(model[-1])\n",
    "learn = Learner(dls, model,  metrics=accuracy)\n",
    "learn.fit_one_cycle(1, 3e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: left;\">\n",
       "      <th>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>valid_loss</th>\n",
       "      <th>accuracy</th>\n",
       "      <th>time</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1.229699</td>\n",
       "      <td>0.689939</td>\n",
       "      <td>0.766667</td>\n",
       "      <td>00:01</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = LSTMPlus(dls.vars, dls.c, dls.len, last_step=False)\n",
    "learn = Learner(dls, model,  metrics=accuracy)\n",
    "learn.fit_one_cycle(1, 3e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: left;\">\n",
       "      <th>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>valid_loss</th>\n",
       "      <th>accuracy</th>\n",
       "      <th>time</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1.657775</td>\n",
       "      <td>1.474122</td>\n",
       "      <td>0.377778</td>\n",
       "      <td>00:02</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "custom_head = partial(create_pool_head, concat_pool=True)\n",
    "model = LSTMPlus(dls.vars, dls.c, dls.len, last_step=False, custom_head=custom_head)\n",
    "learn = Learner(dls, model,  metrics=accuracy)\n",
    "learn.fit_one_cycle(1, 3e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: left;\">\n",
       "      <th>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>valid_loss</th>\n",
       "      <th>accuracy</th>\n",
       "      <th>time</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>0.920532</td>\n",
       "      <td>1.385912</td>\n",
       "      <td>0.600000</td>\n",
       "      <td>00:01</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "custom_head = partial(create_pool_plus_head, concat_pool=True)\n",
    "model = LSTMPlus(dls.vars, dls.c, dls.len, last_step=False, custom_head=custom_head)\n",
    "learn = Learner(dls, model,  metrics=accuracy)\n",
    "learn.fit_one_cycle(1, 3e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RNNPlus(\n",
      "  (backbone): _RNN_Backbone(\n",
      "    (to_cat_embed): Identity()\n",
      "    (feature_extractor): Identity()\n",
      "    (rnn): Sequential(\n",
      "      (0): RNN(3, 100, num_layers=2, batch_first=True, dropout=0.5, bidirectional=True)\n",
      "      (1): LSTMOutput()\n",
      "    )\n",
      "    (transpose): Transpose(dims=-1, -2).contiguous()\n",
      "  )\n",
      "  (head): Sequential(\n",
      "    (0): LastStep()\n",
      "    (1): Dropout(p=0.5, inplace=False)\n",
      "    (2): Linear(in_features=200, out_features=2, bias=True)\n",
      "  )\n",
      ")\n",
      "(81802, True)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([16, 2])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = RNNPlus(c_in, c_out, seq_len, hidden_size=100,n_layers=2,bidirectional=True,rnn_dropout=.5,fc_dropout=.5)\n",
    "print(m)\n",
    "print(total_params(m))\n",
    "m(xb).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LSTMPlus(\n",
      "  (backbone): _RNN_Backbone(\n",
      "    (to_cat_embed): Identity()\n",
      "    (feature_extractor): Identity()\n",
      "    (rnn): Sequential(\n",
      "      (0): LSTM(3, 100, num_layers=2, batch_first=True, dropout=0.5, bidirectional=True)\n",
      "      (1): LSTMOutput()\n",
      "    )\n",
      "    (transpose): Transpose(dims=-1, -2).contiguous()\n",
      "  )\n",
      "  (head): Sequential(\n",
      "    (0): LastStep()\n",
      "    (1): Dropout(p=0.5, inplace=False)\n",
      "    (2): Linear(in_features=200, out_features=2, bias=True)\n",
      "  )\n",
      ")\n",
      "(326002, True)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([16, 2])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = LSTMPlus(c_in, c_out, seq_len, hidden_size=100,n_layers=2,bidirectional=True,rnn_dropout=.5,fc_dropout=.5)\n",
    "print(m)\n",
    "print(total_params(m))\n",
    "m(xb).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "GRUPlus(\n",
      "  (backbone): _RNN_Backbone(\n",
      "    (to_cat_embed): Identity()\n",
      "    (feature_extractor): Identity()\n",
      "    (rnn): Sequential(\n",
      "      (0): GRU(3, 100, num_layers=2, batch_first=True, dropout=0.5, bidirectional=True)\n",
      "      (1): LSTMOutput()\n",
      "    )\n",
      "    (transpose): Transpose(dims=-1, -2).contiguous()\n",
      "  )\n",
      "  (head): Sequential(\n",
      "    (0): LastStep()\n",
      "    (1): Dropout(p=0.5, inplace=False)\n",
      "    (2): Linear(in_features=200, out_features=2, bias=True)\n",
      "  )\n",
      ")\n",
      "(244602, True)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([16, 2])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = GRUPlus(c_in, c_out, seq_len, hidden_size=100,n_layers=2,bidirectional=True,rnn_dropout=.5,fc_dropout=.5)\n",
    "print(m)\n",
    "print(total_params(m))\n",
    "m(xb).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "IPython.notebook.save_checkpoint();"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "105_models.RNNPlus.ipynb saved at 2021-11-24 13:33:39.\n",
      "Converted 105_models.RNNPlus.ipynb.\n",
      "\n",
      "\n",
      "Correct conversion! 😃\n",
      "Total time elapsed 0.093 s\n",
      "Wednesday 24/11/21 13:33:42 CET\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "                <audio  controls=\"controls\" autoplay=\"autoplay\">\n",
       "                    <source src=\"data:audio/wav;base64,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\" type=\"audio/wav\" />\n",
       "                    Your browser does not support the audio element.\n",
       "                </audio>\n",
       "              "
      ],
      "text/plain": [
       "<IPython.lib.display.Audio object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#hide\n",
    "from tsai.imports import create_scripts\n",
    "from tsai.export import get_nb_name\n",
    "nb_name = get_nb_name()\n",
    "create_scripts(nb_name);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
